/*
 build3D.js
 Austin Abrams, Washington University in St. Louis
 5/2/2010
 
 A set of scripts to move 3D points and an incident polygon around the Google Earth Plugin.
 
 Requirements:
 - earth.js
 */

const POLYGON3D_FILL   = '66ffffff';
const POLYGON3D_STROKE = 'ff000000';
const POLYGON3D_LINEWIDTH = 2;

const PREVIOUS3D_FILL   = '33000000';
const PREVIOUS3D_STROKE = 'aaffffff';
const PREVIOUS3D_LINEWIDTH = 3;

// the snap radius.  i.e., if the dragged point comes within snapradius meters
// of another point, the dragged point becomes snapped.
const SNAP_RADIUS_3D = 3.0;

function Build3D() {
	// initialize the toggle buttons.
	this.updateSnap();
	this.updateDepthAssist();
	
	this.polygon = new Polygon3D();
	this.polygon.setStyle(POLYGON3D_FILL, POLYGON3D_STROKE, POLYGON3D_LINEWIDTH);
	this.polygon.buildInCenter();

	this.polygonSet = new Array();
	
	// create other points.
	this.previousPoints = new Array();
	this.previousTriangles = new Array();
	
	// add event handling.
	this.dragged3DPoint = null;
	this.round = 0;

	var me = this;
	google.earth.addEventListener(ge.getGlobe(), "mousedown", function(event){me.geMouseDownHandler(event)});
	google.earth.addEventListener(ge.getGlobe(), "mouseup", function(event){me.geMouseUpHandler(event)});
}

Build3D.prototype.saveAndAdd = function() {
	for ( var i = 0; i < this.polygon.points.length; i++ ) {
		//this.polygon.points[i].undraw();
		this.polygon.points[i].color = 'black';
		this.polygon.points[i].draw();
	}

	this.polygonSet[this.polygonSet.length] = this.polygon;
	this.polygonSet[this.polygonSet.length-1].setStyle(PREVIOUS3D_STROKE, PREVIOUS3D_FILL, PREVIOUS3D_LINEWIDTH);

	this.polygon = new Polygon3D();
	this.polygon.setStyle(POLYGON3D_FILL, POLYGON3D_STROKE, POLYGON3D_LINEWIDTH);
	this.polygon.buildInCenter();
}
Build3D.prototype.discardChanges = function() {
	for ( var i = 0; i < this.polygon.points.length; i++ ) {
		this.polygon.points[i].undraw();
	}
	for ( var i = 0; i < this.polygon.triangles.length; i++ ) {
		this.polygon.triangles[i].undraw();
	}

	for ( var i = 0; i < this.polygonSet.length; i++ ) {
		for ( var j = 0; j < this.polygonSet[i].points.length; j++ ) {
			this.polygonSet[i].points[j].undraw();
		}
		for ( var j = 0; j < this.polygonSet[i].triangles.length; j++ ) {
			this.polygonSet[i].triangles[j].undraw();
		}
	}

	this.polygonSet = new Array();
	this.polygon = new Polygon3D();
	this.polygon.setStyle(POLYGON3D_FILL, POLYGON3D_STROKE, POLYGON3D_LINEWIDTH);
	this.polygon.buildInCenter();
}

Build3D.prototype.polygonsToString = function() {
	var d = "";
	for ( var i = 0; i < this.polygonSet.length; i++ ) {
		d += "Polygon " + i + " of " + this.polygonSet.length + "<br />";
		for ( var j = 0; j < this.polygonSet[i].points.length; j++ ) {
			d += "Point " + j + ": (" + this.polygonSet[i].points[j].lat + ", " + this.polygonSet[i].points[j].lon + ", " + this.polygonSet[i].points[j].alt + ")<br />";
		}
	}
	d += "Current polygon:<br />";
	for ( var i = 0; i < this.polygon.points.length; i++ ) {
		d += "Point " + i + ": (" + this.polygon.points[i].lat + ", " + this.polygon.points[i].lon + ", " + this.polygon.points[i].alt + ")<br />";
	}
	d += "Done.";
}

Build3D.prototype.geMouseMoveHandler = function( event ) {
	if ( this.dragged3DPoint != null ) {
		this.dragged3DPoint.movePoint(event);

		var hitBuilding = hitTestPixelsIsBuilding(event.getClientX(), event.getClientY());
		if ( hitBuilding ) {
			document.getElementById('buildingHitText').style.color = "#777777";
			document.getElementById('groundHitText').style.color = "#B5B5B5";
			this.dragged3DPoint.hitBuilding = true;
		} else {
			document.getElementById('buildingHitText').style.color = "#B5B5B5";
			document.getElementById('groundHitText').style.color = "#777777";
			this.dragged3DPoint.hitBuilding = false;
		} 

		_buildMovedPoint();
		
		var snapping = false;
		if ( document.getElementById('snapbox'))
			snapping = document.getElementById('snapbox').checked;
		
		// if we're snapping, we should see if we're supposed to snap.
		if ( snapping && this.polygon.vertices > 1 ) {
			this.snapPoint3D(this.dragged3DPoint, this.dragged3DPoint.lat, this.dragged3DPoint.lon, this.dragged3DPoint.alt);
		}
		this.polygon.draw()
	} 
}

// handles all google earth mouse down events.
Build3D.prototype.geMouseDownHandler = function( event ) {
	closeAllMenus();

	if ( this.dragged3DPoint != null ) return;

	var poly = this.polygon;
	for ( var i = 0; i < poly.vertices; i++ ) {
		if ( event.getTarget().equals(poly.points[i].placemark) ) {
			this.dragged3DPoint = poly.points[i];

			document.getElementById('hitTestHelperBox').style.borderColor = "#777777";
			if ( this.dragged3DPoint.hitBuilding ) {
				document.getElementById('buildingHitText').style.color = "#777777";
				document.getElementById('groundHitText').style.color = "#B5B5B5";
			} else {
				document.getElementById('buildingHitText').style.color = "#B5B5B5";
				document.getElementById('groundHitText').style.color = "#777777";
			} 

			this.dragged3DPoint.lastY = -1;
			var me = this;
			google.earth.addEventListener(this.dragged3DPoint.placemark, "mousemove", function(event){me.geMouseMoveHandler(event)});
			break;
		}
	}
}

// handles all google earth mouse up events.
Build3D.prototype.geMouseUpHandler = function( event ) {
	document.getElementById('hitTestHelperBox').style.borderColor = "#CCCCCC";
	document.getElementById('buildingHitText').style.color = "#B5B5B5";
	document.getElementById('groundHitText').style.color = "#B5B5B5";

	if ( this.dragged3DPoint != null ) {
		google.earth.removeEventListener(this.dragged3DPoint.placemark, "mousemove", function(event){me.geMouseMoveHandler(event)});
		this.dragged3DPoint = null;
		this.dragged3DPoint.lastY = -1;
	}
}

Build3D.prototype.updateSnap = function() {
	if ( document.getElementById('snapbox') )
		this.snapping = document.getElementById('snapbox').checked;
}

Build3D.prototype.updateDepthAssist = function(){
	if ( document.getElementById('depthbox') )
		this.depthAssist = document.getElementById('depthbox').checked;
}

//checks if the user has moved at least 1 point
Build3D.prototype.movedAPoint = function(){
	for ( var i = 0; i < this.polygon.points.length; i++ ) {
		if ( this.polygon.points[i].movedPoint ){
			return true;
		}
	}
	return false;
}

Build3D.prototype.movedPoints = function() {
	return this.polygon.movedPoints();
}

Build3D.prototype.allPointsHitBuilding = function() { 
	return this.polygon.allPointsHitBuilding();
}

Build3D.prototype.dumpToHTML = function() {
	if ( this.movedPoints() ) {
		this.polygonSet[this.polygonSet.length] = this.polygon;
	}

	var latString = '';
	var lonString = '';
	var altString = '';
	for ( var i = 0; i < this.polygonSet.length; i++ ) {
		for ( var j = 0; j < this.polygonSet[i].points.length; j++ ) {
			latString += this.polygonSet[i].points[j].lat;
			lonString += this.polygonSet[i].points[j].lon;
			altString += this.polygonSet[i].points[j].alt;

			if ( j < this.polygonSet[i].points.length-1 ) {
				latString += ' ';
				lonString += ' ';
				altString += ' ';
			}
		}

		if ( i < this.polygonSet.length-1 ) {
			latString += ';';
			lonString += ';';
			altString += ';';
		}
	}
	document.getElementById("latitudes").value  = latString;
	document.getElementById("longitudes").value = lonString;
	document.getElementById("altitudes").value  = altString;
	
	var camera = ge.getView().copyAsCamera(ge.ALTITUDE_ABSOLUTE);
	document.getElementById("cameraAlt").value = camera.getAltitude();
	document.getElementById("cameraLat").value = camera.getLatitude();
	document.getElementById("cameraLon").value = camera.getLongitude();
	document.getElementById("cameraRoll").value = camera.getRoll();
	document.getElementById("cameraTilt").value = camera.getTilt();
	document.getElementById("cameraHeading").value = camera.getHeading();
}

Build3D.prototype.addPreviousPoint = function( index, lat, lon, alt ) {
	var p = new Point3D(lat, lon, alt, 'black');
	this.previousPoints[index] = p;
}

Build3D.prototype.addPreviousTriangle = function( mapping, triangles ) {
	for (var i = 0; i < triangles.length; i = i + 3){
		var i0 = triangles[i]
		var i1 = triangles[i+1]
		var i2 = triangles[i+2]
		var p0 = this.previousPoints[mapping[i0]]
		var p1 = this.previousPoints[mapping[i1]]
		var p2 = this.previousPoints[mapping[i2]]
		
		var tri = new GETriangle(p0, p1, p2);
		tri.setStyle(PREVIOUS3D_FILL, PREVIOUS3D_STROKE, PREVIOUS3D_LINEWIDTH);
		tri.draw();
		this.previousTriangles[this.previousTriangles.length] = tri;
	}
}

// either snap to the closest point to (lat,lon,alt), or if it's outside the snapping
// radius, move the dragged point to (lat,lon,alt).
Build3D.prototype.snapPoint3D = function( point, lat, lon, alt ) {
	point.snapped = false;

	var smallestRadius = -1;
	var snapPoint = null;
	for (var i in this.previousPoints){
		var otherPoint = this.previousPoints[i];
		var radius = distance(lat,lon,alt,otherPoint.lat,otherPoint.lon,otherPoint.alt)
	   
	   if ((snapPoint == null || radius < smallestRadius)){
		   smallestRadius = radius;
		   snapPoint = otherPoint;
		}
	}
	if (smallestRadius < SNAP_RADIUS_3D && smallestRadius >= 0){
	   point.setLoc(snapPoint.lat, snapPoint.lon, snapPoint.alt);
	   point.snapped = true;
	}
	else{
	   point.setLoc(lat, lon, alt);
	   point.snapped = false;
	}

	for (var i = 0; i < point.parentTriangles.length; i++){
		point.parentTriangles[i].updateEdges();
	}
}